package com.basin.common.mybatisplus.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.basin.common.core.exception.BasinException;
import com.basin.common.core.factory.YmlPropertySourceFactory;
import com.basin.common.mybatisplus.base.BaseIgnoreTenantFieldHandler;
import com.basin.common.mybatisplus.handler.AutoFillHandler;
import com.basin.common.satoken.support.BasinAuthTool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.schema.Column;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.util.List;

/**
 * @author: Sam ZHONG | sammy1997@aliyun.com
 */
@EnableTransactionManagement(proxyTargetClass = true)
@PropertySource(value = "classpath:basin-common-mybatisplus.yml", factory = YmlPropertySourceFactory.class)
@Slf4j
@RequiredArgsConstructor
public class MybatisPlusConfig {
    private final BaseIgnoreTenantFieldHandler baseIgnoreTenantFieldHandler;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 多租户插件
        TenantLineInnerInterceptor tenantLineInnerInterceptor = this.getTenantLineInnerInterceptor();
        interceptor.addInnerInterceptor(tenantLineInnerInterceptor);
        // 分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = this.getPaginationInnerInterceptor();
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        // 乐观锁插件
        OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = this.getOptimisticLockerInnerInterceptor();
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
        // todo 数据权限插件
        return interceptor;
    }

    @Bean
    public MetaObjectHandler injectAutoFillHandler() {
        return new AutoFillHandler();
    }

    private OptimisticLockerInnerInterceptor getOptimisticLockerInnerInterceptor() {
        return new OptimisticLockerInnerInterceptor();
    }

    private PaginationInnerInterceptor getPaginationInnerInterceptor() {
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setOverflow(true);
        return paginationInnerInterceptor;
    }

    private TenantLineInnerInterceptor getTenantLineInnerInterceptor() {
        return new TenantLineInnerInterceptor(new TenantLineHandler() {
            @Override
            public Expression getTenantId() {
                try {
                    return new StringValue(BasinAuthTool.getTenantId());
                } catch (Exception e) {
                    throw new BasinException("获取租户id异常:" + e.getMessage());
                }
            }

            @Override
            public boolean ignoreTable(String tableName) {
                if (baseIgnoreTenantFieldHandler == null) {
                    return false;
                } else {
                    List<String> ignoreTableNameList = baseIgnoreTenantFieldHandler.getIgnoreTableNameList();
                    if (ignoreTableNameList.contains("*")) return true;
                    List<String> ignoreTablePrefixList = baseIgnoreTenantFieldHandler.getIgnoreTablePrefixList();
                    if (ignoreTablePrefixList.contains("*")) return true;
                    return ignoreTableNameList.contains(tableName) ||
                            ignoreTablePrefixList.stream().anyMatch(tableName::startsWith);
                }
            }

            @Override
            public String getTenantIdColumn() {
                // 与mp默认的保持一致
                return "tenant_id";
            }

            @Override
            public boolean ignoreInsert(List<Column> columns, String tenantIdColumn) {
                // 与mp默认的保持一致
                return columns.stream().map(Column::getColumnName).anyMatch(i -> i.equalsIgnoreCase(tenantIdColumn));
            }
        });
    }
}
